﻿namespace LambdaManAi
{
    class DfsSimple : UserFunctions
    {
        public static object MainFunction(params object[] args)
        {
            return Code(() =>
                Pair(1, Closure(StepFunction))
            );
        }

        public static object StepFunction(params object[] args)
        {
            // arguments
            const int stepState = 0;
            const int worldState = 1;

            // locals (should have numbers just after arguments!)
            const int map = 2;
            const int man = 3;
            const int manY = 4;
            const int manX = 5;
            const int maxNeighbor = 6;
            const int nextCell = 7;
            const int curcell = 8;
            const int upcell = 9;
            const int rightcell = 10;
            const int downcell = 11;
            const int leftcell = 12;

            Locals locals = null;
            locals = new Locals(args)
            {
                {map, () => GetItem(locals[worldState], MapStatus)},
                {man, () => GetItem(locals[worldState], ManStatus)},
                {manY, () => GetItem(GetItem(locals[man], 1), 1)},
                {manX, () => GetItem(GetItem(locals[man], 1), 0)},
                {maxNeighbor, () => GetMaxNeighbor(locals[map], locals[manY], locals[manX])},
                {nextCell, () => NextCell(locals[map], locals[manY], locals[manX], 0, -1)},
                {curcell, () =>NormalizeCell(GetCell(locals[map], locals[manY], locals[manX]))},
                {upcell, () => (int)locals[curcell] == Wall ? Wall : NormalizeCell(GetCell(locals[map], (int)locals[manY]-1, locals[manX]))},
                {rightcell, () =>(int)locals[curcell] == Wall ? Wall : NormalizeCell(GetCell(locals[map], locals[manY], (int)locals[manX]+1))},
                {downcell, () =>(int)locals[curcell] == Wall ? Wall : NormalizeCell(GetCell(locals[map], (int)locals[manY]+1, locals[manX]))},
                {leftcell, () =>(int)locals[curcell] == Wall ? Wall : NormalizeCell(GetCell(locals[map], locals[manY], (int)locals[manX]-1))}
            };

            //return Code(locals, () =>
            //    Pair(
            //        List(1, Pair(2, 3), 4, 5, Tuple(6, 7, 8), List()),
            //        Select(
            //            locals[maxNeighbor] == NormalizeCell(GetCell(locals[map], (int)locals[manY] - 1, locals[manX])),
            //            MoveUp,
            //            Select(
            //                locals[maxNeighbor] == NormalizeCell(GetCell(locals[map], locals[manY], (int)locals[manX] + 1)),
            //                MoveRight,
            //                Select(
            //                    locals[maxNeighbor] == NormalizeCell(GetCell(locals[map], (int)locals[manY] + 1, locals[manX])),
            //                    MoveDown,
            //                    MoveLeft
            //                    )
            //                )
            //            )
            //        )
            //);

            //return Code(locals, () =>
            //    Pair(1, Max4Index(
            //        NormalizeCell(GetCell(locals[map], (int)locals[manY] - 1, locals[manX])),
            //        NormalizeCell(GetCell(locals[map], locals[manY], (int)locals[manX] + 1)),
            //        NormalizeCell(GetCell(locals[map], (int)locals[manY] + 1, locals[manX])),
            //        NormalizeCell(GetCell(locals[map], locals[manY], (int)locals[manX] - 1)))
            //    )
            //);

            //return Code(locals, () =>
            //    Pair(1, Max4Index(
            //        CellCost(locals[map], (int)locals[manY] - 1, locals[manX], -1, 1),
            //        CellCost(locals[map], locals[manY], (int)locals[manX] + 1, -1, 1),
            //        CellCost(locals[map], (int)locals[manY] + 1, locals[manX], -1, 1),
            //        CellCost(locals[map], locals[manY], (int)locals[manX] + 1, -1, 1))
            //    )
            //);

            return Code(locals, () => Pair(1, (int)locals[nextCell] >= 0 ? locals[nextCell] :
                ((int)locals[leftcell] != Wall ? MoveLeft :
                ((int)locals[downcell] != Wall ? MoveDown :
                ((int)locals[rightcell] != Wall ? MoveRight : MoveUp)))));
        }

        //Поиск в глубину пилюли, сначала вверх, потом вправо, потом вниз, потом влево
        public static object NextCell(params object[] args)
        {
            const int map = 0;
            const int y = 1;
            const int x = 2;
            const int distance = 3;
            const int prevDirection = 4;
            //locals
            const int curcell = 5;
            const int upcell = 6;
            const int rightcell = 7;
            const int downcell = 8;
            const int leftcell = 9;

            Locals locals = null;
            locals = new Locals(args)
            {
                {curcell, () =>NormalizeCell(GetCell(locals[map], locals[y], locals[x]))},
                {upcell, () => (int)locals[curcell] == Wall ? Wall : NormalizeCell(GetCell(locals[map], (int)locals[y]-1, locals[x]))},
                {rightcell, () =>(int)locals[curcell] == Wall ? Wall : NormalizeCell(GetCell(locals[map], locals[y], (int)locals[x]+1))},
                {downcell, () =>(int)locals[curcell] == Wall ? Wall : NormalizeCell(GetCell(locals[map], (int)locals[y]+1, locals[x]))},
                {leftcell, () =>(int)locals[curcell] == Wall ? Wall : NormalizeCell(GetCell(locals[map], locals[y], (int)locals[x]-1))}
            };

            return Code(locals, () =>
                    Select((int)locals[distance] > 40 || (int)locals[curcell] == Wall, -1,
                        Select((int)locals[upcell] > EmptySpace, MoveUp,
                            Select((int)locals[rightcell] > EmptySpace, MoveRight,
                                Select((int)locals[downcell] > EmptySpace, MoveDown,
                                    Select((int)locals[leftcell] > EmptySpace, MoveLeft,
                                         Select((int)locals[prevDirection] != MoveDown && (int)NextCell(locals[map], (int)locals[y] - 1, locals[x], (int)locals[distance] + 1, MoveUp) >= 0, MoveUp,
                                            Select((int)locals[prevDirection] != MoveLeft && (int)NextCell(locals[map], locals[y], (int)locals[x] + 1, (int)locals[distance] + 1, MoveRight) >= 0, MoveRight,
                                                Select((int)locals[prevDirection] != MoveUp && (int)NextCell(locals[map], (int)locals[y] + 1, (int)locals[x], (int)locals[distance] + 1, MoveDown) >= 0, MoveDown, MoveLeft))))))))
             );
        }
    }
}
